package _20250305;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Test {
    /**
     * 设计一个多线程程序模拟银行转账操作。有多个线程同时进行转账操作，
     * 从一个账户向另一个账户转账一定金额。要求使用锁机制确保转账过程的原子性和线程安全，同时考虑死锁的可能性并避免死锁。
     */
    public static void main(String[] args) {
        Account account1 = new Account(123, 5000);
        Account account2 = new Account(234, 0);

        // 创建多个转账线程
        new Thread(new TransferAccounts(account1, account2, 100)).start();
        new Thread(new TransferAccounts(account2, account1, 200)).start();
    }

    /**
     * 账户类
     */
    private static class Account {
        private final int id; // 账户ID
        private int balance; // 账户余额
        private final Lock lock = new ReentrantLock(); // 账户锁

        public Account(int id, int balance) {
            this.id = id;
            this.balance = balance;
        }

        public int getId() {
            return id;
        }

        public int getBalance() {
            return balance;
        }

        /**
         * 存款
         */
        public void deposit(int amount) {
            lock.lock();
            try {
                balance += amount;
            } finally {
                lock.unlock();
            }
        }

        /**
         * 取款
         */
        public void withdraw(int amount) {
            lock.lock();
            try {
                balance -= amount;
            } finally {
                lock.unlock();
            }
        }
    }

    /**
     * 转账任务
     */
    private static class TransferAccounts implements Runnable {
        private final Account fromAccount; // 转出账户
        private final Account toAccount; // 转入账户
        private final int amount; // 转账金额

        public TransferAccounts(Account fromAccount, Account toAccount, int amount) {
            this.fromAccount = fromAccount;
            this.toAccount = toAccount;
            this.amount = amount;
        }

        @Override
        public void run() {
            transfer(fromAccount, toAccount, amount);
        }

        /**
         * 转账操作
         */
        private void transfer(Account fromAccount, Account toAccount, int amount) {
            // 避免死锁：按账户ID顺序加锁
            Account firstLock = fromAccount.getId() < toAccount.getId() ? fromAccount : toAccount;
            Account secondLock = fromAccount.getId() < toAccount.getId() ? toAccount : fromAccount;

            firstLock.lock.lock();
            try {
                secondLock.lock.lock();
                try {
                    // 检查转出账户余额是否足够
                    if (fromAccount.getBalance() >= amount) {
                        fromAccount.withdraw(amount); // 转出
                        toAccount.deposit(amount); // 转入
                        System.out.println("转账成功：从账户 " + fromAccount.getId() + " 转账 " + amount + " 到账户 " + toAccount.getId());
                    } else {
                        System.out.println("转账失败：账户 " + fromAccount.getId() + " 余额不足");
                    }
                } finally {
                    secondLock.lock.unlock();
                }
            } finally {
                firstLock.lock.unlock();
            }
        }
    }
}